﻿using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace JsonToSql
{
    /// <summary>
    /// Table definition created during the parsing json text
    /// </summary>
    public class JsonTable
    {
        private ReadOnlyCollection<JsonRelation> nmRelations;
        /// <summary>
        /// M:N relations
        /// </summary>
        public ReadOnlyCollection<JsonRelation> NMRelations
        {
            get
            {
                if (nmRelations == null)
                {
                    if (this.Entity == null || this.Entity.Relations == null)
                        return null;
                    nmRelations = new ReadOnlyCollection<JsonRelation>((from item in this.Entity.Relations
                                                                        where item.RelationType == "N:M" ||
                                                                        item.RelationType == "M:N"
                                                                        select item).ToList());
                }
                return nmRelations;
            }
        }
        private JsonEntity entity;
        /// <summary>
        /// Entity definition for this table
        /// </summary>
        public JsonEntity Entity
        {
            get
            {
                if (entity == null)
                {
                    entity = this[Name];
                }
                return entity;
            }
        }
        /// <summary>
        /// Get table by the name
        /// </summary>
        /// <param name="name">name of table</param>
        /// <returns>JsonTable object</returns>
        public JsonTable GetTable(string name)
        {
            for (int i = 0; i < Parent.Tables.Count; i++)
            {
                if (Parent.Tables[i].Name == name)
                {
                    return Parent.Tables[i];
                }
            }
            return null;
        }
        /// <summary>
        /// Return entity definition by the entity name
        /// </summary>
        /// <param name="entityName">Name of entity</param>
        /// <returns>Entity definition</returns>
        public JsonEntity this[string entityName]
        {
            get
            {
                return Parent.Entities[entityName];
            }
        }
        private ReadOnlyCollection<JsonColumn> pkColumns;
        /// <summary>
        /// Primary keys columns
        /// </summary>
        public ReadOnlyCollection<JsonColumn> PKColumns
        {
            get
            {
                if (pkColumns == null)
                {
                    pkColumns = new ReadOnlyCollection<JsonColumn>((from item in Columns.Values.ToList()
                                                                    where item.PrimaryKey == true
                                                                    select item).ToList());
                }
                return pkColumns;
            }
        }
        private ReadOnlyCollection<JsonColumn> valueColumns;
        /// <summary>
        /// Value keys columns - columns wich is not primary keys
        /// </summary>
        public ReadOnlyCollection<JsonColumn> ValueColumns
        {
            get
            {
                if (valueColumns == null)
                {
                    valueColumns = new ReadOnlyCollection<JsonColumn>((from item in CreationColumns
                                                                       where item.PrimaryKey != true

                                                                       select item).ToList());
                }
                return valueColumns;
            }
        }
        private ReadOnlyCollection<JsonColumn> allColumns;
        /// <summary>
        /// All columns
        /// </summary>
        public ReadOnlyCollection<JsonColumn> AllColumns
        {
            get
            {
                if (allColumns == null)
                {
                    allColumns = new ReadOnlyCollection<JsonColumn>((from item in Columns.Values.ToList()
                                                                     select item).ToList());
                }
                return allColumns;
            }
        }
        private ReadOnlyCollection<JsonColumn> creationColumns;
        /// <summary>
        /// Columns which can insert or upadte directly without relation M:N
        /// </summary>
        public ReadOnlyCollection<JsonColumn> CreationColumns
        {
            get
            {
                if (creationColumns == null)
                {
                    creationColumns = new ReadOnlyCollection<JsonColumn>((from item in Columns.Values.ToList()
                                                                          where item.ValueType.Name != "List`1"

                                                                          select item).ToList());
                }
                return creationColumns;
            }
        }
        private Dictionary<string, JsonColumn> columns = new Dictionary<string, JsonColumn>();
        /// <summary>
        /// Columns by name
        /// </summary>
        public Dictionary<string, JsonColumn> Columns
        {
            get
            {
                return columns;
            }
        }
        /// <summary>
        /// Add column by the parsing process
        /// </summary>
        /// <param name="cell">Cell which is parsed</param>
        public void AddColumn(JsonCell cell)
        {
            JsonColumn column = null;
            if (cell == null)
                return;
            if (!this.Columns.ContainsKey(cell.Name))
            {
                column = new JsonColumn();
                column.Name = cell.Name;
                columns.Add(column.Name, column);
            }
            else
            {
                column = this.Columns[cell.Name];
            }

            column.DataType = cell.DataType;
            column.ValueType = cell.ValueType;
            if (cell.MaxLength != null && (column.MaxLength == null || column.MaxLength < cell.MaxLength.Value))
            {
                column.MaxLength = cell.MaxLength;
            }


        }
        private ReadOnlyCollection<JsonRow> rows;
        /// <summary>
        /// All rows of table
        /// </summary>
        public ReadOnlyCollection<JsonRow> Rows
        {
            get
            {
                return rows;
            }
        }
        /// <summary>
        /// Name of table
        /// </summary>
        public string Name
        {
            get
            {
                if (token != null)
                {
                    return token.Path.Substring(2);
                }
                return null;
            }
        }
        private JToken token;
        private JsonRequest parent;
        /// <summary>
        /// Parent request
        /// </summary>
        public JsonRequest Parent
        {
            get
            {
                return parent;
            }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="token">Token text format of table</param>
        /// <param name="parent">Parent request</param>
        public JsonTable(JToken token, JsonRequest parent)
        {
            this.parent = parent;
            this.token = token;
            createKeys();
            createRows();
        }

        private void createKeys()
        {

            for (int i = 0; i < this.Entity.Keys.Count; i++)
            {
                Columns.Add(this.Entity.Keys[i], new JsonColumn()
                    {
                        DataType = Microsoft.SqlServer.Management.Smo.SqlDataType.Int,
                        Name = this.Entity.Keys[i],
                        ValueType = typeof(int),
                        PrimaryKey = true
                    });
            }

        }
        private void createRows()
        {
            if (token != null)
            {
                rows = new ReadOnlyCollection<JsonRow>((from item in token.Values().ToList()
                                                        select new JsonRow(item, this)).ToList());
            }
        }
    }
}
